
#pragma once

#include <ecal/ecal_subscriber.h>

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstddef>
#include <memory>
#include <mutex>
#include <string>
#include <thread>

#include "subscriber_statistics.h"

class Subscriber {
  //////////////////////////////////////
  /// Publisher, Destructor
  //////////////////////////////////////
 public:
  // Constructor that gets a frequency in Hz
  Subscriber(const std::string& topic_name, std::chrono::nanoseconds time_to_waste, bool busy_wait, bool hickup,
             std::chrono::steady_clock::duration wait_before_hickup, std::chrono::steady_clock::duration hickup_delay,
             bool quiet, bool log_print_verbose_times);

  // Delete copy
  Subscriber(const Subscriber&) = delete;
  Subscriber& operator=(const Subscriber&) = delete;

  // Delete move (the class uses a this reference)
  Subscriber(Subscriber&&) noexcept = delete;
  Subscriber& operator=(Subscriber&&) noexcept = delete;

  // Destructor
  ~Subscriber();

  //////////////////////////////////////
  /// Implementation
  //////////////////////////////////////
 private:
  void callback(const char* topic_name_, const eCAL::SReceiveCallbackData* data_);

  void statisticsLoop();

  //////////////////////////////////////
  /// Member variables
  //////////////////////////////////////
 private:
  eCAL::CSubscriber ecal_sub;
  std::chrono::nanoseconds time_to_waste_;
  bool busy_wait_;

  bool hickup_;
  const std::chrono::steady_clock::duration wait_before_hickup_;
  std::chrono::steady_clock::time_point hickup_time_;
  const std::chrono::steady_clock::duration hickup_delay_;

  std::unique_ptr<std::thread> statistics_thread_;
  mutable std::mutex mutex_;
  mutable std::condition_variable condition_variable_;
  std::atomic<bool> is_interrupted_;
  SubscriberStatistics statistics_;
  size_t statistics_size_;

  const bool log_print_verbose_times_;
};
